#region imported Namespaces
using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Text;

using BO = PHSRAG.Insight21.BusinessObjects;
using DataAccess = PHSRAG.Utility.DataAccess;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using SearchCriteria = PHSRAG.Insight21.SearchContext.SearchCriteria;
using ArgumentIndex = PHSRAG.Insight21.Personnel.LaborDistributionArgumentIndex;
using Constants = PHSRAG.Insight21.InsightUtilities.Constants;
#endregion

namespace PHSRAG.Insight21.Personnel
{
	#region Class Labor distributions
	/// <summary>
	/// The LaborDistributions object supports loading of distribution information
	/// for one person to date on one fund (or) personnel who have been paid on given account or fund 
	/// (or) all the people paid on all the funds there are in a given date range (or)
	/// all the people paid to date on funds that the user has access to see
	/// It also exposes methods to support sorting and searching on the retrieved data.
	/// </summary>
	public class LaborDistributions : BO.BusinessObject
	{
		#region Constants
		private const string	LaborDistributionsKey		= "LaborDistributions_B3D9D272-E6D6-476E-8293-A781B6EAD42B";
		private const string	DefaultSortColumn			= "EmployeeName";
        private const string    JobMapIdColumnName          = "EmployeeJobMapId";
        private const int       DomainUserIdArgumentIndex   = 0;
		private const int		DistribTableIndex			= 0;
        private const int       GLTableIndex                = 1;
        private const int       GLTotalTableIndex           = 2;
        private const int       LaborTotalTableIndex        = 3;
       
        #endregion

		#region Instance Variables
		private Hashtable		laborDistributionMap	= new Hashtable();
        private Hashtable       laborDistributionMapGL  = new Hashtable();
        private string          sortColumn              = DefaultSortColumn;
		private string			currentDataTableName	= Constants.OriginalDataTableName;
        private string          glTableName             = Constants.GLTableName;
        private string          glTotalTableName        = Constants.GLTotalTableName;
        private string          laborTotalTableName     = Constants.LaborTotalTableName;
        private bool            sortAscending           = true;
		#endregion

		#region Constructor
		/// <summary>
		/// Intialize the base class with the prevalent cache policy
		/// </summary>
		/// <param name="cachePolicy">The prevalent cache policy</param>
		public LaborDistributions():base(null)
		{
		}
		#endregion

		#region Public Properties

   
		/// <summary>
		/// Get the key to be used in all caching operations for this instance of the object.
		/// </summary>
		public static string CacheKey	{ get { return LaborDistributionsKey; } }
		/// <summary>
		/// Get the total number of Labor distribution rows in the data container.
		/// Returns 0 if there is no data in the data container
		/// </summary>
		public int Count
		{
			get 
			{
				return (DataContainer.Tables.Count == 0)
					  ? 0 : DataContainer.Tables[currentDataTableName].Rows.Count; }
		}

        /// <summary>
        /// Get the total number of Labor distribution rows in the data container.
        /// Returns 0 if there is no data in the data container
        /// </summary>
        public int CountGL
        {
            get
            {
                return (DataContainer.Tables.Count == 0)
                      ? 0 : DataContainer.Tables[glTableName].Rows.Count;
            }
        }

        /// <summary>
        /// Get the total number of Labor distribution rows in the data container.
        /// Returns 0 if there is no data in the data container
        /// </summary>
        public double TotalLabor
        {
            get
            {
                return (DataContainer.Tables.Count == 0)
                      ? 0 : Convert.ToDouble(DataContainer.Tables[laborTotalTableName].Rows[0][0]);
            }
        }

        /// <summary>
        /// Get the total number of Labor distribution rows in the data container.
        /// Returns 0 if there is no data in the data container
        /// </summary>

        public double TotalGL
        {
            get
            {
                return (DataContainer.Tables.Count == 0 || DataContainer.Tables[glTotalTableName].Rows.Count == 0)
                      ? 0 : Convert.ToDouble(DataContainer.Tables[glTotalTableName].Rows[0][0]);
            }
        }

        /// <summary>
		/// Get the sort sequence.
		/// </summary>
		public bool SortAscending
		{
			get { return sortAscending; }
		}

		/// <summary>
		/// Get the name of the sort column.
		/// </summary>
		public string SortColumn
		{
			get { return sortColumn; }
		}
		/// <summary>
		/// Get the table name of the active table in the data container
		/// This will be used for selective downloading of data into reports
		/// </summary>
		public string CurrentDataTableName
		{
			get { return currentDataTableName;}
		}

        /// <summary>
        /// Get the GL table name in the data container
        /// </summary>
        public string GLTableName
        {
            get { return glTableName; }
        }
        /// <summary>
        /// Get the GLTotal table name
        /// </summary>
        public string GLTotalTableName
        {
            get { return glTotalTableName; }
        }
        /// <summary>
        /// Get the LaborTotal table name
        /// </summary>
        public string GLaborTotalTableName
        {
            get { return laborTotalTableName; }
        }

		#endregion

		#region BusinessObject Methods

        private bool IsDate(string sdate)
        {
            try
            {
                DateTime.Parse(sdate);
                return true;
            }
            catch
            {
            }
            return false;
        }


		/// <summary>
		/// Load the Labor distribution data depending on the context in which the user is requesting the data.
		/// The data will be loaded either in context with the Personnel Module or the agreements module
		/// Sort the laoded data on the default sort column
		/// For the load the domain user id is mandatory.
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="args">There are different contexts on which the data has to be loaded
		/// The different scenarios and the mandatory args are listed below
		/// <list type="bullet">
		/// <item><description>DomainUserID is mandatory in all scenarios</description></item>
		/// <item><description>Salaries Overview - FundID and EmployeeJobMapID are mandatory</description></item>
		/// <item><description>Expense Overview - CategoryID and EndDate are mandatory</description></item>
		/// <item><description>Budget Overview-Aggregated Expense to Date salaries - CategoryID is mandatory</description></item>
		/// <item><description>Budget Overview-Accounts within a set of funds aggregated - AccountID is mandatory</description></item>
		/// </list>
		/// </param>
		public override void Load(string connectionString, params object[] args)
		{
			try 
			{
				string sessionID = (string) args[(int)ArgumentIndex.SessionID];
				SearchCriteria searchCriteria = (SearchCriteria) args[(int)ArgumentIndex.SearchCriteria];
				object domainUserID = searchCriteria[InsightUtilities.Constants.DomainUserIDKey];
				if ((domainUserID == null) || ((string)domainUserID == string.Empty || (string)domainUserID == "0"))
					throw new Exception("Labor Distribution load requires a domain user ID");

				Hashtable dictionary = args[2] as Hashtable;
				if (dictionary == null)
					throw new Exception("Labor Distribution load requires additional parameters.");

				if (dictionary[InsightUtilities.Constants.PageNameKey] == null ||
					(dictionary[InsightUtilities.Constants.PageNameKey] == null || (string)dictionary[InsightUtilities.Constants.PageNameKey] == string.Empty))
				{
					DataContainer = DataAccess.GetDataSet(
						connectionString
						,"GetMonthlyLaborDistributionDetails"
						,Utility.DataAccess.BuildSqlParameterArray
						("@domainUserId", SqlDbType.Int, Convert.ToInt32(domainUserID)
						,"@personId", SqlDbType.Int, Convert.ToInt32(dictionary["PersonIdKey"])
						,"@piId", SqlDbType.Int, searchCriteria["PI"]
						// fundNumber is getting passed in as a parameter
						,"@fundNumber", SqlDbType.VarChar, args[3]//searchCriteria["FundID"]
						,"@payStartDate", SqlDbType.DateTime, dictionary["PayStartDateKey"]
						,"@payEndDate", SqlDbType.DateTime, dictionary["PayEndDateKey"]));
				}
                else if (dictionary[InsightUtilities.Constants.PageNameKey].ToString() == "LaborDistribution")
                {
                 string fundNumber = args[3] as String;

                 if (args[0] == null)
                     throw new Exception("AgreementLoadDistribution load requires search criteria containing at least a domain user ID.");


                 if ((searchCriteria[InsightUtilities.Constants.PayFromDateKey] != null) && !IsDate(searchCriteria[InsightUtilities.Constants.PayFromDateKey]))
                     throw new Exception("Pay Date contains an invalid date.");

                 if ((searchCriteria[InsightUtilities.Constants.PayToDateKey] != null) && !IsDate(searchCriteria[InsightUtilities.Constants.PayToDateKey]))
                     throw new Exception("Pay Date contains an invalid date.");

                 if ((searchCriteria[InsightUtilities.Constants.RetroSalaryDateFromKey] != null) && !IsDate(searchCriteria[InsightUtilities.Constants.RetroSalaryDateFromKey]))
                     throw new Exception("Retro Salary Date contains an invalid date.");

                 if ((searchCriteria[InsightUtilities.Constants.RetroSalaryDateToKey] != null) && !IsDate(searchCriteria[InsightUtilities.Constants.RetroSalaryDateFromKey]))
                     throw new Exception("Retro Salary Date contains an invalid date.");

                 if ((searchCriteria[InsightUtilities.Constants.PayFromDateKey] != null) && (searchCriteria[InsightUtilities.Constants.PayToDateKey] != null))
                     if (DateTime.Compare(DateTime.Parse(searchCriteria[InsightUtilities.Constants.PayFromDateKey]), DateTime.Parse(searchCriteria[InsightUtilities.Constants.PayToDateKey])) > 0)
                         throw new Exception("Pay From Date cannot be after Pay End To Date.");

                 if ((searchCriteria[InsightUtilities.Constants.RetroSalaryDateFromKey] != null) && (searchCriteria[InsightUtilities.Constants.RetroSalaryDateToKey] != null))
                     if (DateTime.Compare(DateTime.Parse(searchCriteria[InsightUtilities.Constants.RetroSalaryDateFromKey]), DateTime.Parse(searchCriteria[InsightUtilities.Constants.RetroSalaryDateFromKey])) > 0)
                         throw new Exception("Budget Start From Date cannot be after Budget Start To Date.");

                
                 if (DataContainer != null)
                     DataContainer.Reset();
                //Tfs tkt- 1072
                 DataContainer = DataAccess.GetDataSet(connectionString
                        , "GetAgreementLaborDistributions"
                        , DataAccess.BuildSqlParameterArray(
                          "@sessionID", SqlDbType.VarChar, sessionID
                        , "@domainUserId", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.DomainUserIDKey]
                        , "@fundNumber", SqlDbType.VarChar, (fundNumber == null || fundNumber == string.Empty) ?
                                                            searchCriteria[InsightUtilities.Constants.FundIDKey] : fundNumber
                        , "@categoryID", SqlDbType.Int, dictionary[InsightUtilities.Constants.CategoryIDKey]
                        , "@firstName", SqlDbType.VarChar, searchCriteria[InsightUtilities.Constants.FirstNameKey]
                        , "@lastName", SqlDbType.VarChar, searchCriteria[InsightUtilities.Constants.LastNameKey]
                        , "@jobCode", SqlDbType.VarChar, searchCriteria[InsightUtilities.Constants.JobCodeKey]
                        , "@retroSalaryDateFrom", SqlDbType.DateTime, searchCriteria[InsightUtilities.Constants.RetroSalaryDateFromKey]
                        , "@retroSalaryDateTo", SqlDbType.DateTime, searchCriteria[InsightUtilities.Constants.RetroSalaryDateToKey]
                        , "@paySalaryDateFrom", SqlDbType.DateTime, searchCriteria[InsightUtilities.Constants.PaySalaryDateFromKey]
                        , "@paySalaryDateTo", SqlDbType.DateTime, searchCriteria[InsightUtilities.Constants.PaySalaryDateToKey]
                        , "@payFrequencyType", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.PayFrequencyTypeKey]
                        , "@fundStatus", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.FundStatusKey]
                        
                        ));
                
                }
                else
                {
                    string fundNumber = args[3] as String;
                    if (dictionary[InsightUtilities.Constants.PersonnelConstants.EndDateKey] == null ||
                        (string)dictionary[InsightUtilities.Constants.PersonnelConstants.EndDateKey] == string.Empty)
                        dictionary[InsightUtilities.Constants.PersonnelConstants.EndDateKey] = DateTime.Now.Date;
                        DataContainer = DataAccess.GetDataSet(connectionString
                        , Constants.GetLaborDistributionsSPROCName
                        , DataAccess.BuildSqlParameterArray(
                        "@sessionID", SqlDbType.VarChar, sessionID
                        , "@domainUserId", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.DomainUserIDKey]
                        , "@pageName", SqlDbType.VarChar, dictionary[InsightUtilities.Constants.PageNameKey]
                        , "@employeeJobMapID", SqlDbType.Int, dictionary[InsightUtilities.Constants.PersonnelConstants.EmployeeJobMapIDKey]
                        , "@fundNumber", SqlDbType.VarChar, (fundNumber == null || fundNumber == string.Empty) ?
                                                            searchCriteria[InsightUtilities.Constants.FundIDKey] : fundNumber
                        , "@categoryID", SqlDbType.Int, dictionary[InsightUtilities.Constants.CategoryIDKey]
                        , "@accountID", SqlDbType.Int, dictionary[InsightUtilities.Constants.AccountIDKey]
                        , "@accountNumber", SqlDbType.VarChar, dictionary[InsightUtilities.Constants.AccountNumberKey]
                        , "@monthEndDate", SqlDbType.DateTime, dictionary[InsightUtilities.Constants.PersonnelConstants.EndDateKey]
                        , "@includeProgramProjects", SqlDbType.Bit, searchCriteria[InsightUtilities.Constants.IncludeProgramProjectsKey]
                        , "@folderNumber", SqlDbType.VarChar, searchCriteria[InsightUtilities.Constants.FolderNumberKey]
                        , "@bicsNumber", SqlDbType.VarChar, searchCriteria[InsightUtilities.Constants.BicsNumberKey]
                        , "@walkerNumber", SqlDbType.VarChar, searchCriteria[InsightUtilities.Constants.WalkerNumberKey]
                        , "@sponsorNumber", SqlDbType.VarChar, searchCriteria[InsightUtilities.Constants.SponsorNumberKey]
                        , "@sponsorName", SqlDbType.VarChar, searchCriteria[InsightUtilities.Constants.SponsorNameKey]
                        , "@sponsorTypeId", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.SponsorTypeIDKey]
                        , "@agreementTypeId", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.AgreementTypeIDKey]
                        , "@activityCode", SqlDbType.VarChar, searchCriteria[InsightUtilities.Constants.ActivityCodeKey]
                        , "@locationId", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.LocationIDKey]
                        , "@budgetStartDate", SqlDbType.DateTime, searchCriteria[InsightUtilities.Constants.BudgetStartDateKey]
                        , "@budgetEndDate", SqlDbType.DateTime, searchCriteria[InsightUtilities.Constants.BudgetEndDateKey]
                        , "@projectStartDate", SqlDbType.DateTime, searchCriteria[InsightUtilities.Constants.ProjectStartDateKey]
                        , "@projectEndDate", SqlDbType.DateTime, searchCriteria[InsightUtilities.Constants.ProjectEndDateKey]
                        , "@piId", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.PIIDKey]
                        , "@chiefCodeList", SqlDbType.VarChar, searchCriteria.COSIds
                        , "@sponsorGroupTypeId", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.ViewingOptionKey]
                        , "@budgetEndingDays", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.DaysBudgetEndingKey]
                        , "@projectEndingDays", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.DaysProjectEndingKey]
                        , "@lowBalance", SqlDbType.Decimal, searchCriteria[InsightUtilities.Constants.BalanceLessThanKey]
                        , "@highBalance", SqlDbType.Decimal, searchCriteria[InsightUtilities.Constants.BalanceGreaterThanKey]
                        , "@fundStatusTypeId", SqlDbType.Int, searchCriteria[InsightUtilities.Constants.FundStatusIDKey]
                        , "@agreementStatusTypeList", SqlDbType.VarChar, searchCriteria[InsightUtilities.Constants.AgreementStatusIDKey]
                        , "@currentDateTime", SqlDbType.DateTime, null
                        , "@payrollStartDate", SqlDbType.DateTime, dictionary[InsightUtilities.Constants.PayFromDateKey]
                        , "@payrollEndDate", SqlDbType.DateTime, dictionary[InsightUtilities.Constants.PayToDateKey]
                        , "@isDetail", SqlDbType.Bit, dictionary[InsightUtilities.Constants.AgreementsConstants.IsDetailsKey]
                        , "@cumulative", SqlDbType.Int, Convert.ToInt32(args[4])));
                }
                
                //Tfs tkt- 1072-Start
                if (DataContainer.Tables.Count > 0 )
                {
                    if (DataContainer.Tables.Count >= 4)
                    {
                        DataContainer.Tables[DistribTableIndex].TableName = Constants.OriginalDataTableName;
                        DataContainer.Tables[GLTableIndex].TableName = Constants.GLTableName;
                        DataContainer.Tables[GLTotalTableIndex].TableName = Constants.GLTotalTableName;
                        DataContainer.Tables[LaborTotalTableIndex].TableName = Constants.LaborTotalTableName;
                    }
                    else
                    {
                        DataContainer.Tables[0].TableName = Constants.OriginalDataTableName;
                        DataContainer.Tables[1].TableName = Constants.LaborTotalTableName;
                    
                    }
                }
                //Tfs tkt- 1072-End
                else
					throw new Exception(@"No distribution data found for the user");
				ProcessSort();
			}
			catch(Exception ex)
			{
				throw new Exception(Utility.ExceptionReport.GetExceptionInfo(ex,false));
			}
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Get the list of LaborDistribution objects bound by a start and end index. 
		/// These indeces are into the list of Labor distributions that was loaded during the 
		/// Load() method execution into the data container. Typically, the start index is on 
		/// a "page" boundary, where the "page" referes to a datagrid page.
		/// A Hashtable of ArrayList objects is maintained using the start index as the key. 
		/// This allows retrieval of the set of LaborDistribution objects associated with that 
		/// index, thereby directly supporting random access based the page index.
		/// </summary>
		/// <param name="startIndex">Index within the Labor Distribution list to begin at</param>
		/// <param name="count">Total number of LaborDistribution objects to load</param>
		/// <returns>The list of LaborDistribution objects</returns>
		public ArrayList GetLaborDistributionList(int startIndex, int count)
		{
			ArrayList laborDistributionList = laborDistributionMap[startIndex] as ArrayList;
			if (laborDistributionList == null)
			{
				laborDistributionList = new ArrayList();
				DataTable distributionTable = DataContainer.Tables[currentDataTableName];
				for (int indexCount = startIndex, end = Math.Min(indexCount + count, distributionTable.Rows.Count); indexCount < end; ++indexCount)
					laborDistributionList.Add(new LaborDistribution(CachePolicy,distributionTable.Rows[indexCount]));
				laborDistributionMap[startIndex] = laborDistributionList;
			}
			return laborDistributionList;
		}

        /// <returns>The list of LaborDistributionList objects</returns>
        public ArrayList GetLaborDistributionListGL(int startIndex, int count)
        {
            ArrayList laborDistributionListGL = laborDistributionMapGL[startIndex] as ArrayList;
            if (laborDistributionListGL == null)
            {
                laborDistributionListGL = new ArrayList();
                DataTable distributionTableGL = DataContainer.Tables[glTableName];
                for (int indexCount = startIndex, end = Math.Min(indexCount + count, distributionTableGL.Rows.Count); indexCount < end; ++indexCount)
                    laborDistributionListGL.Add(new LaborDistribution(CachePolicy, distributionTableGL.Rows[indexCount]));
                laborDistributionMapGL[startIndex] = laborDistributionListGL;
            }
            return laborDistributionListGL;
        }
        
		/// <summary>
		/// Search the DataContainer for rows which match the specified search criteria.
		/// Two DataTables are maintained within the DataContainer; a full-complement DataTable and a filtered one.
		/// This allows filtering without having to hit the database. If a filter is in
		/// effect, we simply set the value of the currentTableName to Constants.FilteredDataTableName so that the
		/// GetLaborDIstributionList() method may retreive from the appropriate DataTable.
		/// </summary>
		/// <param name="searchCriteria">The search criteria instance picked from the search context</param>
		/// <remarks>True if the search criteria did any filtering; false otherwise</remarks>
		public bool Search(SearchCriteria searchCriteria)
		{
			laborDistributionMap.Clear();

			StringBuilder filter = new StringBuilder();

			foreach (string key in searchCriteria.Keys)
			{
				switch (key.ToLower())
				{
					case "employeefirstname":
						filter.AppendFormat("{0} FirstName LIKE '{1}%'",(filter.Length>0)?"AND":"",searchCriteria[key]);
						break;
					case "employeelastname":
						filter.AppendFormat("{0} LastName LIKE '{1}%'",(filter.Length>0)?"AND":"",searchCriteria[key]);
						break;					
					case "paydatefrom":
						filter.AppendFormat("{0} PayDate>='{1}'",(filter.Length>0)?"AND":"",searchCriteria[key]);
						break;
					case "paydateto":
						filter.AppendFormat("{0} PayDate<='{1}'",(filter.Length>0)?"AND":"",searchCriteria[key]);
						break;
					case "pi":
						filter.AppendFormat("{0} PrincipalInvestigatorId ='{1}'",(filter.Length>0)?"AND":"",searchCriteria[key]);
						break;
				}
			}

			bool applySearch = (filter.Length > 0);
			if(applySearch)
			{
				DataTable distributionTable = DataContainer.Tables[Constants.OriginalDataTableName];
				DataTable filteredDataTable = distributionTable.Clone();
				filteredDataTable.TableName = currentDataTableName = Constants.FilteredDataTableName;

				DataRow[] filteredRows = distributionTable.Select(filter.ToString(), String.Format("{0} {1}", 
					sortColumn, sortAscending ? Constants.SortOrderAscending : Constants.SortOrderDescending));

				foreach (DataRow distributionRow in filteredRows)
					filteredDataTable.ImportRow(distributionRow);

				if (DataContainer.Tables.Contains(Constants.FilteredDataTableName))
					DataContainer.Tables.Remove(Constants.FilteredDataTableName);
				DataContainer.Tables.Add(filteredDataTable);
			}
			else
				currentDataTableName = Constants.OriginalDataTableName;

			return applySearch;
		}
		/// <summary>
		/// Sort the list of Labor distributions by the speicified column.
		/// If the column is to be sorted is the same as what was last sorted on, the sort sequence is toggled. Else, the
		/// sort sequence is set to ascending.
		/// </summary>
		/// <param name="columnName">Column to sort by</param>
		public void Sort(string columnName)
		{
			laborDistributionMap.Clear();

			sortAscending = (sortColumn == columnName) ? !sortAscending : true;
			sortColumn = columnName;
			
			ProcessSort();			
		}

        /// <summary>
        /// Sort the GL list of Labor distributions by the speicified column.
        /// </summary>
        public void SortGL(string columnName)
        {
            laborDistributionMapGL.Clear();

            sortAscending = (sortColumn == columnName) ? !sortAscending : true;
            sortColumn = columnName;

            ProcessSortGL();
        }

		#endregion

		#region Private methods
		/// <summary>
		/// Sorts the current data table on the sortColumn instance variable
		/// in the order specified by the sortOrder instance variable
		/// </summary>
		private void ProcessSort()
		{
			DataTable distributionTable = DataContainer.Tables[currentDataTableName];
			DataView distributionView = distributionTable.DefaultView;
			distributionView.Sort = string.Format("{0} {1}", 
				sortColumn, sortAscending ? Constants.SortOrderAscending : Constants.SortOrderDescending);

			DataTable sortedDataTable = distributionTable.Clone();
			foreach (DataRowView distributionRowView in distributionView)
				sortedDataTable.ImportRow(distributionRowView.Row);

			if(DataContainer.Tables.Contains(currentDataTableName))
				DataContainer.Tables.Remove(currentDataTableName);
			
			DataContainer.Tables.Add(sortedDataTable);
		}

        private void ProcessSortGL()
        {
            DataTable distributionTableGL = DataContainer.Tables[glTableName];
            DataView distributionViewGL = distributionTableGL.DefaultView;
            distributionViewGL.Sort = string.Format("{0} {1}",
                sortColumn, sortAscending ? Constants.SortOrderAscending : Constants.SortOrderDescending);

            DataTable sortedDataTableGL = distributionTableGL.Clone();
            foreach (DataRowView distributionRowViewGL in distributionViewGL)
                sortedDataTableGL.ImportRow(distributionRowViewGL.Row);

            if (DataContainer.Tables.Contains(glTableName))
                DataContainer.Tables.Remove(glTableName);

            DataContainer.Tables.Add(sortedDataTableGL);
        }

		#endregion
	}
	#endregion
}